//
//  IKFileCrypto.m
//  RemoteDLNA
//
//  Created by fanzhang on 2017/5/9.
//  Copyright © 2017年 IK. All rights reserved.
//

#import "IKMusicFileCrypto.h"
#import <NSString+MIHConversion.h>
#import <MIHAESKey.h>
#import <MIHAESKeyFactory.h>
#import <openssl/aes.h>
#import <NSData+MIHConversion.h>
#import "FCBasics.h"

@implementation IKMusicFileCrypto

+ (BOOL)encryptFile:(NSString*)fromFile toFile:(NSString*)toFile key:(NSString*)key iv:(NSString*)iv
{
    NSParameterAssert([[NSFileManager defaultManager] fileExistsAtPath:fromFile]);
    NSParameterAssert(toFile.length);
    NSParameterAssert(key.length == (MIHAESKey256 * 2));
    NSParameterAssert(iv.length == (AES_BLOCK_SIZE * 2));
    
    BOOL ret = NO;
    {
        // aes encrypt
        NSData* rawKey = [key MIH_dataFromHexadecimal];
        if (!(rawKey.length == MIHAESKey256)) {
            goto IKExit;
        }
        NSData* rawIv = [iv MIH_dataFromHexadecimal];
        if (!(rawIv.length == AES_BLOCK_SIZE)) {
            goto IKExit;
        }
        MIHAESKey* aes = [[MIHAESKey alloc] initWithKey:rawKey iv:rawIv];
        
        NSData* fromData = [NSData dataWithContentsOfFile:fromFile];
        if (!(fromData.length > 0)) {
            goto IKExit;
        }
        
        NSError* error;
        NSData* resultData = [aes encrypt:fromData error:&error];
        if (!(!error && resultData.length >= fromData.length && resultData.length % AES_BLOCK_SIZE == 0)) {
            goto IKExit;
        }

        // rolling XOR
        UInt64* pBegin = (UInt64*)resultData.bytes;
        UInt64* pEnd = pBegin + resultData.length / sizeof(UInt64);
        while (pBegin < (pEnd - 1))
        {
            *pBegin ^= *(pBegin + 1);
            ++pBegin;
        }
        
        ret = [resultData writeToFile:toFile atomically:YES];
        if (!(ret)) {
            goto IKExit;
        }
        
        ret = YES;
    }
    
IKExit:
    return ret;
}

+ (BOOL)decryptFile:(NSString*)fromFile toFile:(NSString*)toFile key:(NSString*)key iv:(NSString*)iv
{
    NSParameterAssert([[NSFileManager defaultManager] fileExistsAtPath:fromFile]);
    NSParameterAssert(toFile.length);
    NSParameterAssert(key.length == (MIHAESKey256 * 2));
    NSParameterAssert(iv.length == (AES_BLOCK_SIZE * 2));
    
    BOOL ret = NO;
    {
        NSData* rawKey = [key MIH_dataFromHexadecimal];
        if (!(rawKey.length == MIHAESKey256)) {
            goto IKExit;
        }
        NSData* rawIv = [iv MIH_dataFromHexadecimal];
        if (!(rawIv.length == AES_BLOCK_SIZE)) {
            goto IKExit;
        }
        MIHAESKey* aes = [[MIHAESKey alloc] initWithKey:rawKey iv:rawIv];
        
        NSData* fromData = [NSData dataWithContentsOfFile:fromFile];
        if (!(fromData.length > 0 && fromData.length % AES_BLOCK_SIZE == 0)) {
            goto IKExit;
        }
        
        // reverse rolling XOR
        UInt64* pREnd = (UInt64*)fromData.bytes;
        UInt64* pRBegin = pREnd + fromData.length / sizeof(UInt64) - 1;
        while (pRBegin > pREnd)
        {
            *(pRBegin - 1) ^= *pRBegin;
            --pRBegin;
        }
        
        // aes decrypt
        NSError* error;
        NSData* resultData = [aes decrypt:fromData error:&error];
        if (!(!error && resultData.length <= fromData.length)) {
            goto IKExit;
        }
        
        ret = [resultData writeToFile:toFile atomically:YES];
        if (!(ret)) {
            goto IKExit;
        }
        
        ret = YES;
    }
    
IKExit:
    return ret;
}

@end

